package com.example.datachangerecord.record.processor;


import com.example.datachangerecord.record.annotation.Record;
import com.example.datachangerecord.record.eneity.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author xyj
 */
@Component
public class RequestRecordProcessor extends CompareRecordProcessor {

    @Qualifier("noDoDecorator")
    @Autowired
    private LogBodyDecorate decorate;


    @SneakyThrows
    protected Method getMethodByJointPoint(ProceedingJoinPoint jp) {
        Class<?> targetCls = jp.getTarget().getClass();
        MethodSignature ms = (MethodSignature) jp.getSignature();
        return targetCls.getDeclaredMethod(
                ms.getName(),
                ms.getParameterTypes());
    }

    private List<? extends ContextRecordData> addRequest(List<? extends ContextRecordData> lists, HttpServletRequest request) {
        if (CollectionUtils.isEmpty(lists)) {
            return lists;
        }
        List<RequestContextRecordData> result = new ArrayList<>(lists.size());
        lists.forEach(e -> {
            RequestContextRecordData requestContextRecordData = new RequestContextRecordData();
            requestContextRecordData.setRequest(request);
            requestContextRecordData.setTable(e.getTable());
            requestContextRecordData.setPerData(e.getPerData());
            requestContextRecordData.setAfterData(e.getAfterData());
            result.add(requestContextRecordData);
        });

        return result;
    }

    public List<? extends ContextRecordData> beforeProceed(ProceedingJoinPoint jp, HttpServletRequest request) {

        List<? extends ContextRecordData> data = super.beforeProceed(getMethodByJointPoint(jp), jp.getArgs());

        return addRequest(data, request);

    }

    @Override
    protected void afterCustom(List<? extends ContextRecordData> contexts) {

        Date currentTime = new Date();

        for (ContextRecordData e : contexts) {
            analyseRequest((RequestContextRecordData) e, currentTime);
        }

    }

    private void analyseRequest(RequestContextRecordData requestContext, Date time) {
        HttpServletRequest request = requestContext.getRequest();
        String remoteAddr = getIpAddr(request);
        requestContext.setUserId(request.getHeader("userId"));
        requestContext.setUserName(request.getHeader("userName"));
        requestContext.setIp(remoteAddr);
        requestContext.setOperateTime(time);
    }

    private String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if ("127.0.0.1".equals(ipAddress)) {
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    assert inet != null;
                    ipAddress = inet.getHostAddress();
                }
            }
            if (ipAddress != null && ipAddress.length() > 15) {
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }
        return ipAddress;
    }


    @SneakyThrows
    @Override
    protected UpdateUser getUpdateUser(ContextRecordData context) {
        RequestContextRecordData requestContext = (RequestContextRecordData) context;
        String userName = requestContext.getUserName();

        String decode = "";
        if (userName != null) {
            decode = URLDecoder.decode(userName, "UTF-8");
        }
        return UpdateUser.builder()
                .userId(requestContext.getUserId())
                .userName(decode)
                .ip(requestContext.getIp())
                .build();
    }

    @Override
    public void record(List<LogBody> lists) {
        Date now = new Date();
        lists.forEach(

                e -> {
                    e.setOperateDate(now);
                    beRecordLogService.save(e);
                }
        );
    }

    @Override
    public void decorate(List<LogBody> body) {
        decorate.decorate(body);
    }

    @Override
    protected void addPerMainDesc(LinkedHashMap<String, Object> per, LogBody logBody, Table table) {
        //do nothing
    }

    @Override
    protected void beforeProcessRecord(Method method, Object[] args, Record record) {
        super.beforeProcessRecord(method, args, record);
    }
}
